package com.example.coffeeseller_2.model.helper;

import com.example.coffeeseller_2.model.beans.CoffeeMakeStateRecorder;
import com.example.coffeeseller_2.model.beans.DealRecorder;
import com.example.coffeeseller_2.model.factory.CoffeeMakeState;
import com.example.coffeeseller_2.model.listenner.MkCoffeeListenner;
import com.example.coffeeseller_2.model.listenner.OnMakeCoffeeProcessListenner;
import com.example.coffeeseller_2.utils.JinzhiSwitcher;
import com.example.coffeeseller_2.utils.MyLog;
import com.example.coffeeseller_2.utils.Waiter;

import java.util.List;

import cof.ac.inter.CoffMsger;
import cof.ac.inter.ContainerConfig;
import cof.ac.inter.MachineState;
import cof.ac.inter.Result;
import cof.ac.inter.StateEnum;

/**
 * Created by WH on 2018/8/11.
 */

public class MkCoffeeHelper {

    private static String TAG = "MkCoffeeHelper";
    private long MAX_TOTAL_MK_TIME = 180000;
    private long MAX_STATE_TIME = 5000;
    private CoffeeMakeStateRecorder coffeeMakeStateRecorder;
    private MkCoffeeListenner mkCoffeeListenner;
    private OnMakeCoffeeProcessListenner onMakeCoffeeProcessListenner;
    private CoffMsger coffMsger;
    private long lastStateTime;
    private long startMakingTime;
    private boolean isCalculateMaterial = true;//是否计算落料量


    public MkCoffeeHelper() {

        init();
    }

    private void clear() {
        lastStateTime = 0;
        startMakingTime = 0;
        isCalculateMaterial = true;
        if (coffeeMakeStateRecorder != null) {
        } else {
            coffeeMakeStateRecorder = new CoffeeMakeStateRecorder();
        }
        coffeeMakeStateRecorder.init();
    }

    private void init() {

        coffMsger = CoffMsger.getInstance();
    }

    public void setMkProcessListenner(OnMakeCoffeeProcessListenner onMakeCoffeeProcessListenner) {

        this.onMakeCoffeeProcessListenner = onMakeCoffeeProcessListenner;
    }

    public void setMkResultListenner(MkCoffeeListenner mkCoffeeListenner) {
        this.mkCoffeeListenner = mkCoffeeListenner;
    }

    public void startMkCoffee(List<ContainerConfig> containerConfigs) {

        if (containerConfigs == null) {
            MyLog.W(TAG, "containerConfigs is null,will not start mkcoffee");
            return;
        }
        clear();
        //   initTime();
        if (containerConfigs != null && containerConfigs.size() > 0) {
            mkCoffee(containerConfigs);
        } else {
            MyLog.W(TAG, "containerConfigs is null,will not start mkcoffee");
        }

    }

    /*
    * 制作咖啡
    * */
    private void mkCoffee(final List<ContainerConfig> containerConfigs) {

        MyLog.W(TAG, "the statebyte before mk is :\n" + coffMsger.getLastMachineState().getMajorState().getHighErr_byte());

        MyLog.W(TAG, "start making");

        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                MachineState machineState = null;
                lastStateTime = System.currentTimeMillis();
                startMakingTime = System.currentTimeMillis();
                while (true) {
                    Waiter.doWait(200);
                    machineState = coffMsger.getLastMachineState();
                    if (isMkTimeOut()) {

                        dealMkTimeOut(machineState);
                        break;
                    }
                    if (DealMachineState(machineState)) {

                        if (machineState.getMajorState().getCurStateEnum() == StateEnum.HAS_ERR) {

                            dealHasErr(machineState);
                        }
                    } else {
                        continue;
                    }

                    if (coffeeMakeStateRecorder.state == null) {

                        Result result = coffMsger.mkCoffee(containerConfigs);
                        MyLog.d(TAG, "send mkCoffee comd : ");
                        sendMkCoffeeResult(machineState, result);
                        continue;
                    } else if (coffeeMakeStateRecorder.state == CoffeeMakeState.COFFEE_MAKE_INIT) {

                        dealStateMakeInit(machineState);
                        continue;
                    } else if (coffeeMakeStateRecorder.state == CoffeeMakeState.COFFEE_DOWN_CUP) {

                        dealStateDownCup(machineState);
                        continue;
                    } else if (coffeeMakeStateRecorder.state == CoffeeMakeState.COFFEE_ISMAKING) {

                        dealMakingState(machineState);
                        continue;
                    } else if (coffeeMakeStateRecorder.state == CoffeeMakeState.COFFEE_DOWN_POWER) {

                        dealStateDownPower(machineState);
                        continue;
                    } else if (coffeeMakeStateRecorder.state == CoffeeMakeState.COFFEEFINISHED_CUPNOTAKEN) {

                        dealCupNotTaken();
                        break;
                    } else if (coffeeMakeStateRecorder.state == CoffeeMakeState.COFFEEFINISHED_CUPISTAKEN) {

                        coffeeMakeStateRecorder.state = null;
                        break;
                    } else if (coffeeMakeStateRecorder.state == CoffeeMakeState.COFFEEMAKING_FAILED) {

                        dealMakingFailed();
                        MyLog.d(TAG, "cur state is failed ");
                        break;
                    }
                }
            }
        };
        new Thread(runnable).start();
    }

    private boolean isTimeOut() {

        long curTime = System.currentTimeMillis();
        if (curTime - lastStateTime > MAX_STATE_TIME) {

            MyLog.W(TAG, "5s内接收的状态没有更新");
            return true;
        }
        return false;
    }

    /*
    * 制作总时长是否超时
    * */
    private boolean isMkTimeOut() {

        return System.currentTimeMillis() - startMakingTime > MAX_TOTAL_MK_TIME;
    }

    /*
 * 制作过程超时后的处理
 * */
    private void dealMkTimeOut(MachineState machineState) {

        if (coffeeMakeStateRecorder.state == null
                || coffeeMakeStateRecorder.state == CoffeeMakeState.COFFEEFINISHED_CUPNOTAKEN
                || coffeeMakeStateRecorder.state == CoffeeMakeState.COFFEEFINISHED_CUPISTAKEN) {

            MyLog.W(TAG, " make successed but time is too long ");
        } else {
            if (coffeeMakeStateRecorder.state == CoffeeMakeState.COFFEE_DOWN_CUP || coffeeMakeStateRecorder.state == CoffeeMakeState.COFFEE_MAKE_INIT) {

                MyLog.W(TAG, " make failed and time is too long," + coffeeMakeStateRecorder.state + "  state is remaining ");

                DealRecorder.getInstance().setMakeSuccess(false);
                isCalculateMaterial = false;

                DealRecorder.getInstance().setErrCode("制作超时！");
                if (mkCoffeeListenner != null)
                    mkCoffeeListenner.getMkResult(DealRecorder.getInstance(), false, isCalculateMaterial);

                return;

            } else if (coffeeMakeStateRecorder.state == CoffeeMakeState.COFFEE_ISMAKING
                    || coffeeMakeStateRecorder.state == CoffeeMakeState.COFFEE_DOWN_POWER) {

                MyLog.W(TAG, " make failed and time is too long," + coffeeMakeStateRecorder.state + " state is remaining ");

                if (machineState.hasCupOnShelf()) {
                    DealRecorder.getInstance().setMakeSuccess(false);
                } else {
                    DealRecorder.getInstance().setMakeSuccess(true);
                }
                isCalculateMaterial = true;
                if (mkCoffeeListenner != null) {
                    mkCoffeeListenner.getMkResult(DealRecorder.getInstance(), DealRecorder.getInstance().isMakeSuccess(), isCalculateMaterial);
                }

                return;

            }
        }
    }

    private boolean DealMachineState(MachineState curState) {

        if (curState.getResult().getCode() == Result.SUCCESS) {

            lastStateTime = System.currentTimeMillis();
            return true;
        } else {
            if (isTimeOut()) {
                DealRecorder.getInstance().setErrCode("not receive state into 5 s");
                coffeeMakeStateRecorder.state = CoffeeMakeState.COFFEEMAKING_FAILED;
                isCalculateMaterial = false;
            }
            return false;
        }
    }

    private void dealHasErr(MachineState machineState) {
    /*
    * 如果接收到0a时，出现的状态是落杯或初始化
    * */
        if (coffeeMakeStateRecorder.state == CoffeeMakeState.COFFEE_DOWN_CUP || coffeeMakeStateRecorder.state == CoffeeMakeState.COFFEE_MAKE_INIT) {
            isCalculateMaterial = false;

        }
        coffeeMakeStateRecorder.state = CoffeeMakeState.COFFEEMAKING_FAILED;

        DealRecorder.getInstance().setErrCode(JinzhiSwitcher.byte2Hex(machineState.getMajorState().getHighErr_byte()) + "");

        MyLog.W(TAG, "制作过程中接收到0a : " + machineState.getMajorState().getHighErr_byte() + "--" + machineState.getMajorState().getLowErr_byte());

        MyLog.W(TAG, "machineState return hasErr, err msg : " + machineState.getResult().getReturn_bytes());


    }

    private void sendMkCoffeeResult(MachineState machineState, Result result) {
        MyLog.W(TAG, "mk result = " + result.getReturn_bytes());
        if (result.getCode() == Result.SUCCESS) {

            coffeeMakeStateRecorder.state = CoffeeMakeState.COFFEE_MAKE_INIT;
            isCalculateMaterial = false;
            initState();
            MyLog.W(TAG, " cur state is init");

        } else {

            MyLog.W(TAG, "send mkCoffee comd result = " + result.getCode() + " resultId= " + result.getId()
                    + " \n send mkCoffee comd err return : " + result.getReturn_bytes());


            isCalculateMaterial = false;

            MyLog.W(TAG, "发送咖啡制作指令，返回" + result.getErrDes());
            MyLog.W(TAG, " resultId= " + result.getId() + " send mkCoffee comd err return : " + result.getReturn_bytes());

            DealRecorder.getInstance().setErrCode(result.getErrDes() + "");
            coffeeMakeStateRecorder.state = CoffeeMakeState.COFFEEMAKING_FAILED;
            failed();
        }
    }

    protected void dealStateMakeInit(MachineState machineState) {

        if (machineState.getMajorState().getCurStateEnum() == StateEnum.DOWN_CUP) {

            coffeeMakeStateRecorder.state = CoffeeMakeState.COFFEE_DOWN_CUP;
            downCup();

            MyLog.W(TAG, " cur state is down cup");
        }
    }

    protected void dealStateDownCup(MachineState machineState) {

        if (machineState.getMajorState().getCurStateEnum() == StateEnum.MAKING) {

            coffeeMakeStateRecorder.state = CoffeeMakeState.COFFEE_ISMAKING;
            making();
            MyLog.W(TAG, " cur state is making");
        } else if (machineState.getMajorState().getCurStateEnum() == StateEnum.DOWN_POWDER) {

            coffeeMakeStateRecorder.state = CoffeeMakeState.COFFEE_DOWN_POWER;
            downPower();
            MyLog.W(TAG, " cur state is down power");
        } else if (machineState.getMajorState().getCurStateEnum() == StateEnum.FINISH) {

            coffeeMakeStateRecorder.state = CoffeeMakeState.COFFEEFINISHED_CUPNOTAKEN;
            finish();
            MyLog.W(TAG, " cur state is finish");
        }

    }

    private boolean dealMakingState(MachineState machineState) {

        isCalculateMaterial = true;
        if (machineState.getMajorState().getCurStateEnum() == StateEnum.DOWN_POWDER) {

            coffeeMakeStateRecorder.state = CoffeeMakeState.COFFEE_DOWN_POWER;
            downPower();
            MyLog.W(TAG, " cur state is down power");
            return true;
        } else if (machineState.getMajorState().getCurStateEnum() == StateEnum.FINISH) {

            coffeeMakeStateRecorder.state = CoffeeMakeState.COFFEEFINISHED_CUPNOTAKEN;
            finish();
            MyLog.W(TAG, " cur state is finish");
            return true;
        }

        return false;
    }

    protected void dealStateDownPower(MachineState machineState) {

        isCalculateMaterial = true;
        if (machineState.getMajorState().getCurStateEnum() == StateEnum.MAKING) {

            coffeeMakeStateRecorder.state = CoffeeMakeState.COFFEE_ISMAKING;
            making();
            MyLog.W(TAG, " cur state is making");
        } else if (machineState.getMajorState().getCurStateEnum() == StateEnum.FINISH) {

            coffeeMakeStateRecorder.state = CoffeeMakeState.COFFEEFINISHED_CUPNOTAKEN;
            finish();
            MyLog.W(TAG, " cur state is finish");
        }
    }

    private void dealCupNotTaken() {

        isCalculateMaterial = true;
        MyLog.W(TAG, "mk success,will upload ,wait 0s,the machine state is : \n" + coffMsger.getLastMachineState().getResult().getReturn_bytes());

        //上报交易记录
        DealRecorder.getInstance().setMakeSuccess(true);
        if (mkCoffeeListenner != null) {
            mkCoffeeListenner.getMkResult(DealRecorder.getInstance(), true, isCalculateMaterial);
        }
    }

    private void dealMakingFailed() {

        MyLog.W(TAG, "mk failed ,wait 0s,the machine state is : \n" + coffMsger.getLastMachineState().getResult().getReturn_bytes());

        DealRecorder.getInstance().setMakeSuccess(false);
        if (mkCoffeeListenner != null) {
            mkCoffeeListenner.getMkResult(DealRecorder.getInstance(), false, isCalculateMaterial);
        }
    }

    private void initState() {
        if (onMakeCoffeeProcessListenner != null) {
            onMakeCoffeeProcessListenner.init();
        }
    }

    private void downCup() {
        if (onMakeCoffeeProcessListenner != null) {
            onMakeCoffeeProcessListenner.downCup();
        }
    }

    private void downPower() {
        if (onMakeCoffeeProcessListenner != null) {
            onMakeCoffeeProcessListenner.downPower();
        }
    }

    private void making() {
        if (onMakeCoffeeProcessListenner != null) {
            onMakeCoffeeProcessListenner.making();
        }
    }

    private void finish() {
        if (onMakeCoffeeProcessListenner != null) {
            onMakeCoffeeProcessListenner.finish();
        }
    }

    private void failed() {
        if (onMakeCoffeeProcessListenner != null) {
            onMakeCoffeeProcessListenner.failed();
        }
    }
}
